use std::collections::HashSet;

type Coord = (i32, i32);

#[derive(Debug)]
enum Instruction {
    FoldX(i32),
    FoldY(i32),
}

fn parse_input() -> (HashSet<Coord>, Vec<Instruction>) {
    let input = std::fs::read_to_string("./day13/input.txt").unwrap();
    
    let coords = input.split("\r\n\r\n").nth(0).unwrap();
    let coords = coords.lines().map(|line| -> Coord {
        // 55,870
        let index = line.find(',').unwrap();
        ((&line[..index]).parse().unwrap(), (&line[index+1..]).parse().unwrap())
    }).collect();

    let instructions = input.split("\r\n\r\n").nth(1).unwrap();
    let instructions = instructions.lines().map(|line| -> Instruction {
        let inst_type = line.chars().nth(11).unwrap();
        let position = line[13..].parse().unwrap();
        match inst_type {
            'x' => Instruction::FoldX(position),
            'y' => Instruction::FoldY(position),
            _   => panic!("")
        }
    }).collect();

    (coords, instructions)
}

fn fold_paper(coords: HashSet<Coord>, instruction: &Instruction) -> HashSet<Coord> {
    match instruction {
        Instruction::FoldX(position) => coords.into_iter().map(|(x, y)| -> Coord {
            // No change y
            // (x + x') / 2 == pos => x' = 2 * pos - x
            if x < *position { (x, y) } else { (2 * position - x, y) }
        }).collect(),
        Instruction::FoldY(position) => coords.into_iter().map(|(x, y)| -> Coord {
            if y < *position { (x, y) } else { (x, 2 * position - y) }
        }).collect(),
    }
}

#[allow(unused)]
fn part1(coords: HashSet<Coord>, instructions: &Vec<Instruction>) {
    let instruction = &instructions[0];
    let coords = fold_paper(coords, instruction);
    println!("Part1: {}", coords.len());
}

#[allow(unused)]
fn part2(coords: HashSet<Coord>, instructions: &Vec<Instruction>) {
    let coords = instructions.iter().fold(coords, fold_paper);

    let max_x = coords.iter().max_by_key(|(x, y)| x).unwrap().0;
    let max_y = coords.iter().max_by_key(|(x, y)| y).unwrap().1;

    println!("Part2:");
    for y in 0..=max_y {
        for x in 0..=max_x {
            if coords.contains(&(x, y)) {
                print!("█");
            } else {
                print!(" ");
            }
        }
        println!("");
    }
}

fn main() {
    let (coords, instructions) = parse_input();
    part1(coords.clone(), &instructions);
    part2(coords, &instructions);
}
